package com.zudada.servermain.Service.ServiceImpl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.zudada.servermain.POJO.DTO.DateStatsQueryDTO;
import com.zudada.servermain.POJO.DTO.StatsQueryDTO;
import com.zudada.servermain.POJO.VO.PeriodStatsVO;
import com.zudada.servermain.POJO.VO.PortOperationStatsVO;
import com.zudada.servermain.POJO.VO.ReportVO;
import com.zudada.servermain.POJO.entity.PortOperationStats;
import com.zudada.servermain.Service.PortStatsService;
import com.zudada.servermain.common.constant.PortStatsMessageConstant;
import com.zudada.servermain.exception.BusinessException;
import com.zudada.servermain.mapper.PortOperationStatsMapper;
import com.zudada.servermain.mapper.VesselBerthingMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Service
public class PortStatsServiceImpl implements PortStatsService {

    @Autowired
    private VesselBerthingMapper vesselBerthingMapper;

    @Autowired
    private PortOperationStatsMapper statsMapper;


    /**
     * 计算并保存指定周期的港口吞吐量统计
     *
     * @param periodType 周期类型（DAY/WEEK/MONTH/YEAR）
     */
    public void calculateAndSaveStats(String periodType) {
        // 1. 调用Mapper获取汇总数据
        List<PortOperationStatsVO> voList = vesselBerthingMapper.sumCargoByPortAndPeriod(periodType);
        if (CollectionUtils.isEmpty(voList)) {
            return;
        }
        // 2. 转换为PortOperationStats实体并保存
        for (PortOperationStatsVO vo : voList) {
            PortOperationStats stats = new PortOperationStats();
            // 生成唯一statsId（港口ID + 周期 + 前缀）
            stats.setStatsId(vo.getPortId() + "_" + vo.getStatsPeriod() + "_STAT");
            stats.setPortId(vo.getPortId());
            stats.setStatsPeriod(vo.getStatsPeriod());
            stats.setThroughput(vo.getThroughput());  // 吞吐量
            stats.setVesselCount(vo.getVesselCount());  // 船舶数
            stats.setServiceRating(new BigDecimal("4.5"));  // 示例默认评分（实际需从其他表获取）
            stats.setCreateTime(LocalDateTime.now());

            // 3. 插入或更新（存在则更新，不存在则新增）
            if (statsMapper.selectById(stats.getStatsId()) != null) {
                statsMapper.updateById(stats);  // 更新
            } else {
                statsMapper.insert(stats);  // 新增
            }
        }
    }

    @Override
    public List<PeriodStatsVO> getStatsByPeriod(StatsQueryDTO statsQueryDTO) {
        try {
            // 业务规则校验：查询条件不能为空
            if (statsQueryDTO == null) {
                throw new BusinessException(PortStatsMessageConstant.PARAM_ERROR);
            }
            return statsMapper.selectByPeriod(statsQueryDTO);
        } catch (BusinessException e) {
            // 业务异常直接抛出
            throw e;
        } catch (Exception e) {
            log.error("查询港口统计数据失败，未知异常：{}", e.getMessage(), e);
            throw new BusinessException(PortStatsMessageConstant.QUERY_STATS_FAILED);
        }
    }

    @Override
    public ReportVO getThroughputStats(DateStatsQueryDTO queryDTO) {
        try {
            // 参数校验（Controller层已通过@Valid校验，此处保留作为防御性编程）
            if (queryDTO == null) {
                throw new BusinessException(PortStatsMessageConstant.PARAM_ERROR);
            }

            // 1. 解析日期列表
            List<String> dateList = parseDateList(queryDTO.getDateList());

            // 2. 查询数据
            List<PeriodStatsVO> statsList = statsMapper.selectThroughputByDateList(
                    queryDTO.getPortId(), dateList);

            // 3. 转换为 ReportVO
            return convertToReportVO(statsList, dateList, true);
        } catch (BusinessException e) {
            // 业务异常直接抛出
            throw e;
        } catch (IllegalArgumentException e) {
            log.error("查询吞吐量统计失败，日期格式异常：{}", e.getMessage());
            throw new BusinessException(PortStatsMessageConstant.DATE_LIST_FORMAT_ERROR);
        } catch (Exception e) {
            log.error("查询吞吐量统计失败，未知异常：{}", e.getMessage(), e);
            throw new BusinessException(PortStatsMessageConstant.QUERY_THROUGHPUT_FAILED);
        }
    }

    @Override
    public ReportVO getVesselCountStats(DateStatsQueryDTO queryDTO) {
        try {
            // 参数校验（Controller层已通过@Valid校验，此处保留作为防御性编程）
            if (queryDTO == null) {
                throw new BusinessException(PortStatsMessageConstant.PARAM_ERROR);
            }

            // 1. 解析日期列表
            List<String> dateList = parseDateList(queryDTO.getDateList());

            // 2. 查询数据
            List<PeriodStatsVO> statsList = statsMapper.selectVesselCountByDateList(
                    queryDTO.getPortId(), dateList);

            // 3. 转换为 ReportVO
            return convertToReportVO(statsList, dateList, false);
        } catch (BusinessException e) {
            // 业务异常直接抛出
            throw e;
        } catch (IllegalArgumentException e) {
            log.error("查询船舶数统计失败，日期格式异常：{}", e.getMessage());
            throw new BusinessException(PortStatsMessageConstant.DATE_LIST_FORMAT_ERROR);
        } catch (Exception e) {
            log.error("查询船舶数统计失败，未知异常：{}", e.getMessage(), e);
            throw new BusinessException(PortStatsMessageConstant.QUERY_VESSEL_COUNT_FAILED);
        }
    }

    /**
     * 解析日期列表字符串（逗号分隔）为 List
     * @param dateListStr 日期字符串，例如：2022-10-01,2022-10-02,2022-10-03
     * @return 日期列表
     */
    private List<String> parseDateList(String dateListStr) {
        if (!StringUtils.hasText(dateListStr)) {
            return new ArrayList<>();
        }
        return Arrays.stream(dateListStr.split(","))
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .collect(Collectors.toList());
    }

    /**
     * 将统计数据转换为 ReportVO
     * @param statsList 统计数据列表
     * @param dateList 日期列表（用于构建 xAxis）
     * @param isThroughput true表示吞吐量，false表示船舶数
     * @return ReportVO
     */
    private ReportVO convertToReportVO(List<PeriodStatsVO> statsList, List<String> dateList, boolean isThroughput) {
        ReportVO reportVO = new ReportVO();

        // 1. 设置 xAxis（使用传入的日期列表，如果没有则从统计数据中提取）
        List<String> xAxis;
        if (CollectionUtils.isNotEmpty(dateList)) {
            xAxis = new ArrayList<>(dateList);
        } else {
            xAxis = statsList.stream()
                    .map(PeriodStatsVO::getTimeLabel)
                    .distinct()
                    .sorted()
                    .collect(Collectors.toList());
        }
        reportVO.setXAxis(xAxis);

        // 2. 构建数据映射（portId -> timeLabel -> value）
        Map<String, Map<String, Object>> portDataMap = new HashMap<>();
        for (PeriodStatsVO vo : statsList) {
            String portId = vo.getPortId();
            String timeLabel = vo.getTimeLabel();
            Object value = isThroughput ? vo.getThroughput() : vo.getVesselCount();

            portDataMap.computeIfAbsent(portId, k -> new HashMap<>()).put(timeLabel, value);
        }

        // 3. 构建 series
        List<ReportVO.SeriesData> seriesList = new ArrayList<>();

        if (portDataMap.isEmpty()) {
            // 如果没有数据，返回空系列
            reportVO.setSeries(seriesList);
            return reportVO;
        }

        // 判断是单个港口还是多个港口
        if (portDataMap.size() == 1) {
            // 单个港口：创建一个系列
            String portId = portDataMap.keySet().iterator().next();
            Map<String, Object> dataMap = portDataMap.get(portId);

            ReportVO.SeriesData series = new ReportVO.SeriesData();
            series.setName(isThroughput ? "吞吐量" : "船舶数");
            series.setType(isThroughput ? "line" : "bar");
            series.setData(buildDataArray(xAxis, dataMap));
            seriesList.add(series);
        } else {
            // 多个港口：每个港口一个系列
            for (Map.Entry<String, Map<String, Object>> entry : portDataMap.entrySet()) {
                String portId = entry.getKey();
                Map<String, Object> dataMap = entry.getValue();

                ReportVO.SeriesData series = new ReportVO.SeriesData();
                series.setName("港口-" + portId);
                series.setType(isThroughput ? "line" : "bar");
                series.setData(buildDataArray(xAxis, dataMap));
                seriesList.add(series);
            }
        }

        reportVO.setSeries(seriesList);
        return reportVO;
    }

    /**
     * 根据 xAxis 和数据映射构建数据数组
     * @param xAxis 时间轴数组
     * @param dataMap 数据映射（timeLabel -> value）
     * @return 数据数组
     */
    private List<Object> buildDataArray(List<String> xAxis, Map<String, Object> dataMap) {
        List<Object> data = new ArrayList<>();
        for (String timeLabel : xAxis) {
            data.add(dataMap.getOrDefault(timeLabel, null));
        }
        return data;
    }
}
